home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Interactive 7
/
PC World Interactive 7.iso
/
program
/
ctutor.exe
/
TEXT
/
CHAP05.TXT
< prev
next >
Wrap
Text File
|
1994-05-15
|
35KB
|
696 lines
Chapter 5
FUNCTIONS, VARIABLES, AND PROTOTYPES
OUR FIRST USER DEFINED FUNCTION
-----------------------------------------------------------------
Load and examine the file SUMSQRES.C for an ================
example of a C program with functions. SUMSQRES.C
Actually this is not the first function we ================
have encountered because the main program we
have been using all along is technically a function, as is the
printf() function. The printf() function is a library function
that was supplied with your compiler.
Notice the executable part of this program which begins in line 8
with a line that simply says "header();", which is the way to
call any function. The parentheses are required because the C
compiler uses them to determine that it is a function call and
not simply a misplaced variable. When the program comes to this
line of code, the function named header() is called, its
statements are executed, and control returns to the statement
following this call. Continuing on, we come to a for loop which
will be executed 7 times and which calls another function named
square() each time through the loop, and finally a function named
ending() will be called and executed. For the moment ignore the
variable name index in the parentheses of the call to square. We
have seen that this program calls a header, 7 square calls, and
an ending. Now we need to define the functions.
DEFINING THE FUNCTIONS
-----------------------------------------------------------------
Following the main program you will see another program beginning
in line 14 that follows all of the rules set forth so far for a
main program except that it is named header(). This is the
function which is called from line 8 of the main program. Each
of these statements are executed, and when they are all complete,
control returns to the main program. The first statement sets the
variable named sum equal to zero because we plan to use it to
accumulate a sum of squares. Since the variable named sum is
defined prior to the main program, it is available for use in any
of the functions which are defined after the variable is defined.
It is called a global variable, and its scope is the entire
program including all functions. It is also sometimes referred
to as a file variable because it is available throughout the
file. More will be said about the scope of variables near the
end of this chapter. The statement in line 17 outputs a header
message to the monitor. Program control then returns to the main
program since there are no additional statements to execute in
this function. Essentially, we drop out of the bottom of the
function and return to the caller.
Page 5-1
Chapter 5 - Functions, Variables, and Prototypes
It should be clear to you that the two executable lines from this
function could be moved to the main program, replacing the header
call, and the program would do exactly the same thing that it
does as it is now written. This does not minimize the value of
functions, it merely illustrates the operation of this simple
function in a simple way. You will find functions to be very
valuable in C programming.
PASSING A VALUE TO A FUNCTION (CLASSIC METHOD)
-----------------------------------------------------------------
Going back to the main program, and the for loop specifically, we
find the new construct from the end of the last lesson used in
the last part of the for loop, namely the index++ used in line 9.
You should get familiar with this construct, as you will see it
in a lot of C programs. In the call to the function named
square(), we have an added feature, the variable name index
within the parentheses. This is an indication to the compiler
that when you jump to the function, you wish to take along the
value of index to use in the execution of that function. Looking
ahead at the function named square() in line 20, we find that
another variable name is enclosed in its parentheses, the
variable number. This is the name we prefer to call the variable
passed to the function when we are in the function. We can call
it anything we wish as long as it follows the rules of naming an
identifier. Since the function must know what type the variable
is, it is defined following the function name but before the
opening brace of the function itself. Therefore, line 21
containing the expression "int number;" tells the function that
the value passed to it will be an integer type variable. With
all of that out of the way, we now have the value of index from
the main program passed to the function square(), but renamed
number, and available for use within the function. This is the
classic style of defining function variables and has been in use
since C was originally defined. A newer, and much better, method
is gaining in popularity due to its many benefits and will be
discussed later in this chapter.
Following the opening brace of the function, we define another
variable named numsq for use only within the function itself,
(more about that later) and proceed with the required
calculations. We set the variable named numsq equal to the
square of the value of number, then add numsq to the current
total stored in the variable named sum. You should remember
that the expression "sum += numsq;" has the same meaning as
"sum = sum + numsq;" from the last lesson. We print the number
and its square in line 27, and return to the main program.
MORE ABOUT PASSING A VALUE TO A FUNCTION
-----------------------------------------------------------------
When we passed the value of the variable named index to the
function, a little more happened than meets the eye. We didn't
Page 5-2
Chapter 5 - Functions, Variables, and Prototypes
pass the variable named index to the function, we actually passed
a copy of the value. In this way the original value is protected
from accidental corruption by the called function. We could have
modified the variable named number in any way we wished in the
function named square(), and when we returned to the main
program, the variable named index would not have been modified.
We thus protect the value of a variable in the calling function
from being accidentally corrupted, but we cannot return a value
to the calling function from a called function using this
technique. We will find a well defined method of returning
values to the main program or to any calling function when we get
to arrays and another method when we get to pointers. Until
then, the only way you will be able to communicate back to the
calling function will be with global variables. We have already
hinted at global variables above, and will discuss them in detail
later in this chapter.
Continuing in the main program, we come to the last function
call, the call to the function named ending() in line 11. This
line calls the last function which has no local variables
defined. It prints out a message with the value of the variable
sum contained in it to end the program. The program ends by
returning to the main program and finding nothing else to do.
Compile and run this program and observe the output.
NOW TO CONFESS A LITTLE LIE
-----------------------------------------------------------------
I told you a short time ago that the only way ===============
to get a value back to the main program was SQUARES.C
through use of a global variable, but there is ===============
another way which we will discuss after you
load and display the program named SQUARES.C. In this example
program we will see that it is simple to return a single value
from a called function to the calling function. But once again,
it is true that to return more than one value, we will need to
study either arrays or pointers.
In the main program, we define two integers and begin a for loop
in line 6 which will be executed 8 times. The first statement of
the for loop is "y = squ(x);", which is a new and rather strange
looking construct. From past experience, we should have no
trouble understanding that the squ(x) portion of the statement is
a call to the function named squ() taking along the value of x as
a variable. Looking ahead to line 15 of the function itself, we
find that the function prefers to call the input variable input,
and it proceeds to square the value of input and call the result
square. Finally, a new kind of a statement appears in line 21,
the return statement. The value within the parentheses is
assigned to the function itself and is returned as a usable value
in the main program. Thus, the function call "squ(x)" is
assigned the value of the square and returned to the main program
such that the variable named y is then set equal to that value.
Page 5-3
Chapter 5 - Functions, Variables, and Prototypes
If the variable named x were therefore assigned the value 4 prior
to this call, y would then be set to 16 as a result of the code
in line 7.
Another way to think of this is to consider the grouping of
characters squ(x) as another variable with a value that is the
square of x, and this new variable can be used any place it is
legal to use a variable of its type. The values of the variables
x and y are then printed out.
To illustrate that the grouping of squ(x) can be thought of as
just another variable, another for loop is introduced in line 11
in which the function call is placed in the printf() statement
rather than assigning it to a new variable.
One last point must be made, the type of variable returned must
be defined in order to make sense of the data, but the compiler
will default the type to int if none is specified. If any other
type is desired, it must be explicitly defined. How to do this
will be demonstrated in the next example program. We are simply
using the default return value in this program.
Be sure to compile and run this program which also uses the
classic method of defining function variables. Once again, any
warnings can be ignored.
FLOATING POINT FUNCTIONS
-----------------------------------------------------------------
Load the program FLOATSQ.C for an example of a ===============
function with a floating point type of return. FLOATSQ.C
It begins by defining a global floating point ===============
variable named z which we will use later.
Then in the main part of the program, an integer is defined,
followed by two floating point variables, and then by two strange
looking definitions. The expressions sqr() and glsqr() look like
function calls and they are. This is the proper way in C to
define that a function will return a value that is not of type
int, but of some other type, in this case float. This tells the
compiler that when a value is returned from either of these two
functions, it will be of type float. This is, once again, the
classic method of defining functions and is all but obsolete now.
Now refer to the function named sqr() starting in line 22 and you
will see that the function name is preceded by the keyword float.
This is an indication to the compiler that this function will
return a value of type float to any program that calls it. The
type of the function return is now compatible with the call to
it. The line following the function name contains float inval;,
which indicates to the compiler that the variable passed to this
function from the calling program will be of type float.
Page 5-4
Chapter 5 - Functions, Variables, and Prototypes
The function named glsqr() beginning in line 31, will also return
a float type variable, but it uses a global variable for input.
It does the squaring right within the return statement and
therefore has no need to define a separate variable to store the
product.
The overall structure of this program should pose no problem and
will not be discussed in any further detail. As is customary
with all example programs, compile and run this program.
THE CLASSIC STYLE
-----------------------------------------------------------------
The three programs we have studied in this chapter so far use the
classic style of function definition. Although this was the
first style defined for C, it is rapidly being replaced with a
more modern method of function definition because the modern
method does so much for you in detecting and flagging errors.
As you read articles on C, you will see programs written in the
classic style, so you need to be capable of reading them. This
is the reason the classic style was included in this chapter. It
would be highly recommended, however, that you learn and use the
modern method which will be covered shortly in this tutorial. In
fact, you are advised to never use the classic style for any of
your programming efforts.
The remainder of this tutorial will use the modern method as
recommended and defined by the ANSI standard. If you have an
older compiler, it may not work on some of these files and it
will be up to you to modify the programs as needed to conform to
the classic style. Actually, the ANSI standard is used so
universally, if you have a non-ANSI compiler you should use it
only as a doorstop and purchase a good ANSI compatible compiler
for the rest of your studies.
SCOPE OF VARIABLES
-----------------------------------------------------------------
Load the next program, SCOPE.C, and display it ===============
for a discussion of the scope of variables in a SCOPE.C
program. You can ignore the 4 statements in ===============
lines 2 through 5 of this program for a few
moments. We will discuss them later.
The variable defined in line 7 is a global variable named count
which is available to any function in the program since it is
defined before any of the functions. It is always available
because it exists during all the time that the program is being
executed. (That will make sense shortly.) Farther down in the
program, another global variable named counter is defined in line
25 which is also global but is not available to the main program
since it is defined following the main program. A global
variable is any variable that is defined outside of any function.
Page 5-5
Chapter 5 - Functions, Variables, and Prototypes
Note that both of these variables are sometimes referred to as
external variables because they are external to any functions,
and they are sometimes also called file variables.
Return to the main program and you will see the variable named
index defined as an integer in line 11. Ignore the word register
for the moment. This variable is only available within the main
program because that is where it is defined. In addition, it is
an automatic variable, which means that it only comes into
existence when the function in which it is contained is invoked,
and ceases to exist when the function is finished. This really
means nothing here because the main program is always in
operation, even when it gives control to another function.
Another integer is defined within the for loop braces named
stuff. Any pairing of braces can contain variable definitions
which will be valid and available only while the program is
executing statements within those braces. The variables will be
automatic variables and will cease to exist when execution leaves
the braces. This is convenient to use for a loop counter or some
other very localized variable.
MORE ON AUTOMATIC VARIABLES
-----------------------------------------------------------------
Observe the function named head1() in line 26 which looks a
little funny because of void being used twice. The purpose of
the use of the word void will be explained shortly. The function
contains a variable named index, which has nothing to do with the
variable named index in line 11 of the main program, except that
both are automatic variables. When the program is not actually
executing statements in this function, this variable named index
does not even exist. When head1() is called, the variable is
generated, and when head1() completes its task, the variable in
head1() named index is eliminated completely from existence.
(The automatic variable is stored on the stack. This topic will
be covered later.) Keep in mind however that this does not
affect the variable of the same name in the main program, since
it is a completely separate entity.
Automatic variables therefore, are automatically generated and
disposed of when needed. The important thing to remember is that
from one call of a function to the next call, the value of an
automatic variable is not preserved and must therefore be
reinitialized.
WHAT ARE STATIC VARIABLES?
-----------------------------------------------------------------
An additional variable type must be mentioned at this point, the
static variable. By putting the keyword static in front of a
variable definition within a function, the variable or variables
in that definition are static variables and will stay in
existence from call to call of the particular function. A static
Page 5-6
Chapter 5 - Functions, Variables, and Prototypes
variable is initialized once, at load time, and is never
reinitialized during execution of the program.
By putting the static keyword in front of an external variable,
one outside of any function, it makes the variable private and
not accessible to use in any other file. (This is a completely
different use of the same keyword.) This implies that it is
possible to refer to external variables in other separately
compiled files, and that is true. Examples of this usage will be
given in chapter 14 of this tutorial.
USING THE SAME NAME AGAIN
-----------------------------------------------------------------
Refer to the function named head2(). It contains another
definition of the variable named count. Even though count has
already been defined as a global variable in line 7, it is
perfectly all right to reuse the name in this function. It is a
completely new variable that has nothing to do with the global
variable of the same name, and causes the global variable to be
unavailable within this function. This allows you to write
programs using existing functions without worrying about what
names were used for global variables or in other functions
because there can be no conflict. You only need to worry about
the variables that interface with the functions.
WHAT IS A REGISTER VARIABLE?
-----------------------------------------------------------------
Now to fulfill a promise made earlier about what a register
variable is. A computer can keep data in a register or in
memory. A register is much faster in operation than memory but
there are very few registers available for the programmer to use.
If there are certain variables that are used extensively in a
program, you can designate that those variables are to be stored
in a register in order to speed up the execution of the program.
The method of doing this is illustrated in line 11. Your
compiler probably allows you to use one or more register
variables and will ignore additional requests if you request more
than are available. The documentation for your compiler should
list how many registers are available with your compiler. It
will also inform you of what types of variables can be stored in
a register. If your compiler does not allow the use of register
variables, the register request will simply be ignored.
WHERE DO I DEFINE VARIABLES?
-----------------------------------------------------------------
Now for a refinement on a general rule stated earlier. When you
have variables brought to a function as arguments to the
function, and you are using the classic style of programming,
they are defined immediately after the function name and prior to
the opening brace for the executable statements. Local variables
Page 5-7
Chapter 5 - Functions, Variables, and Prototypes
used in the function are defined at the beginning of the
function, immediately following the opening brace of the
function, and before any executable statements.
WHAT IS PROTOTYPING?
-----------------------------------------------------------------
A prototype is a model of a real thing and when programming with
a good up-to-date C compiler, you have the ability to define a
model of each function for the compiler. The compiler can then
use the model to check each of your calls to the function and
determine if you have used the correct number of arguments in the
function call and if they are of the correct type. By using
prototypes, you let the compiler do some additional error
checking for you. The ANSI standard for C contains prototyping
as part of its recommended standard. Every good C compiler will
have prototyping available, so you should learn to use it. Much
more will be said about prototyping throughout the remainder of
this tutorial.
Returning to lines 3, 4, and 5 in SCOPE.C, we have the prototypes
for the three functions contained within the program. The first
void in each line tells the compiler that these particular
functions do not return a value, so that the compiler would flag
the statement index = head1(); as an error because nothing is
returned to assign to the variable named index. The word void
within the parentheses tells the compiler that this function
requires no parameters and if a variable were included, it would
be an error and the compiler would issue a warning message. If
you wrote the statement head1(index);, it would be a error. This
allows you to use type checking when programming in C in much the
same manner that it is used in Pascal, Modula-2, or Ada, although
the type checking in C is relatively weak.
Note the addition of the word void in line 9. This is an
indication to the system that we do not plan to return a value to
the operating system when we terminate operation of this program.
The main program also can return an int value in the same manner
as any other function. This value is returned to the operating
system where it can be ignored or it's value used as an
indication of what the program did.
You may have been getting warning messages when you compiled many
of the example programs in this tutorial, and you now see the
reasons for these warnings. The compiler was telling you that it
did not know how to handle the lack of a return definition. This
will be fixed in all of the remaining example programs in this
tutorial.
You should begin using prototype checking at this time, if it is
available with your compiler. Your compiler may have an option
that will require a prototype for every function. This should be
enabled and left enabled. Check your documentation for the
Page 5-8
Chapter 5 - Functions, Variables, and Prototypes
details of how to do it. Prototyping will be used throughout the
remainder of this tutorial. If your compiler does not support
prototyping and the modern method of function definition, you
will have to modify the remaining example programs. A much
better solution would be to purchase a better compiler.
Line 2 of SCOPE.C tells the system to go to the standard
directory where include files are stored and get the file named
STDIO.H which contains the prototypes for the standard input and
output functions so they can be checked for proper variable
types. Don't worry about the include yet, it will be covered in
detail later in this tutorial. Be sure to compile and execute
this program. If you have been getting warnings about the
function printf() not being defined, it is fixed by including
the stdio.h file as we have done here. We will explain why this
fixes the warnings shortly.
STANDARD FUNCTION LIBRARIES
-----------------------------------------------------------------
Every compiler comes with some standard predefined functions
which are available for your use. These are mostly input/output
functions, character and string manipulation functions, and math
functions. We will cover most of these in subsequent chapters.
Prototypes are defined for you by the writer of your compiler for
all of the functions that are included with your compiler. A few
minutes spent studying your reference guide will give you an
insight in where the prototypes are defined for each of the
functions.
Most compilers have additional functions predefined that are not
standard but allow the programmer to get the most out of his
particular computer. In the case of the IBM-PC and compatibles,
most of these functions allow the programmer to use the BIOS
services available in the operating system, or to write directly
to the video monitor or to any place in memory. These will not
be covered in any detail as you will be able to study these
unique aspects of your compiler on your own. Several of these
kinds of functions are used in the example programs in chapter
14.
WHAT IS RECURSION?
-----------------------------------------------------------------
Recursion is another of those programming ================
techniques that seem very intimidating the RECURSON.C
first time you come across it, but if you will ================
load and display the example program named
RECURSON.C, we will take all of the mystery out of it. This is
probably the simplest recursive program that it is possible to
write and it is therefore a stupid program in actual practice,
but for purposes of illustration, it is excellent.
Page 5-9
Chapter 5 - Functions, Variables, and Prototypes
Recursion is nothing more than a function that calls itself. It
is therefore in a loop which must have a way of terminating. In
the program on your monitor, the variable named index is set to 8
in line 9, and is used as the argument to the function named
count_dn(). The function simply decrements the variable, prints
it out in a message, and if the variable is not zero, it calls
itself, where it decrements the variable again, prints it, etc.
etc. etc. Finally, the variable will reach zero, and the
function will not call itself again. Instead, it will return to
the prior time it called itself, and return again, and again,
until finally it will return to the main program and from there
return to DOS.
For purposes of understanding you can think of it as having 8
copies of the function named count_dn() available and it simply
called all of them one at a time, keeping track of which copy it
was in at any given time. That is not what actually happened,
but it is a reasonable illustration for you to begin
understanding what it was really doing.
WHAT DID IT DO?
-----------------------------------------------------------------
A better explanation of what actually happened is in order. When
you called the function from itself, it stored all of the
variables and all of the internal flags it needs to complete the
function in a block somewhere. The next time it called itself,
it did the same thing, creating and storing another block of
everything it needed to complete that function call. It
continued making these blocks and storing them away until it
reached the last function when it started retrieving the blocks
of data, and using them to complete each function call. The
blocks were stored on an internal part of the computer called the
stack. This is a part of memory carefully organized to store
data just as described above. It is beyond the scope of this
tutorial to describe the stack in detail, but it would be good
for your programming experience to read some material describing
the stack. A stack is used in nearly all modern computers for
internal housekeeping chores.
In using recursion, you may desire to write a program with
indirect recursion as opposed to the direct recursion described
above. Indirect recursion would be when a function A calls the
function B, which in turn calls A, etc. This is entirely
permissible, the system will take care of putting the necessary
things on the stack and retrieving them when needed again. There
is no reason why you could not have three functions calling each
other in a circle, or four, or five, etc. The C compiler will
take care of all of the details for you.
The thing you must remember about recursion is that at some
point, something must go to zero, or reach some predefined point
to terminate the loop. If not, you will have an infinite loop,
Page 5-10
Chapter 5 - Functions, Variables, and Prototypes
and the stack will fill up and overflow, giving you an error and
stopping the program rather abruptly.
ANOTHER EXAMPLE OF RECURSION
-----------------------------------------------------------------
The program named BACKWARD.C is another example ==============
of recursion, so load it and display it on your BACKWARD.C
screen at this time. This program is similar ==============
to the last one except that it uses a character
array. Each successive call to the function named
forward_and_backwards() causes one character of the message to be
printed. Additionally, each time the function ends, one of the
characters is printed again, this time backwards as the string of
recursive function calls is retraced.
This program uses the modern method of function definition and
includes full prototype definitions. The modern method of
function definition moves the types of the variables into the
parentheses along with the variable names themselves. The final
result is that the line containing the function definition looks
more like the corresponding line in a language with relatively
strong type checking such as Pascal, Modula-2, or Ada. The
prototype in line 5 is simply a copy of the function header in
line 18 followed by a semicolon. The designers of C even allow
you to include a variable name along with each type. The name is
ignored by the compiler but including the name in the prototype
could give you a good idea of how the variable is used, acting
like a comment.
Don't worry about the character array defined in line 9 or the
other new material presented here. After you complete chapter 7
of this tutorial, this program will make sense. It was felt that
introducing a second example of recursion was important so this
file is included here.
Compile and run this program with prototype checking enabled and
observe the results.
THE FLOAT SQUARE PROGRAM WITH PROTOTYPES
-----------------------------------------------------------------
Load and display the program named FLOATSQ2.C ================
which is an exact copy of the program FLOATSQ.C FLOATSQ2.C
which we considered earlier with prototyping ================
added. The use of prototyping is a good
practice for all C programmers to get into. Several things
should be mentioned about this program. First, the word float at
the beginning of lines 27 and 35 indicate to the compiler that
these functions are functions that return float type values.
Also, since the prototypes are given before main, the functions
are not required to be identified in line 12 as they were in line
7 of FLOATSQ.C earlier in this chapter. Notice also that the
Page 5-11
Chapter 5 - Functions, Variables, and Prototypes
type of the variable named inval is included within the
parentheses in line 27.
Now that we understand prototypes, we can eliminate most of the
warnings we have been getting during our study of this tutorial.
It would be good practice for you to eliminate all warnings in
all of your programs, since the compiler is trying to warn you of
some potentially bad programming constructs.
MORE STYLE ISSUES
-----------------------------------------------------------------
The example named STYLE2.C is given as an ================
illustration of various ways to format a STYLE2.C
function. You will note different ways to ================
define the input parameters. Examples three
and four are both the same style, but example four illustrates
the style when nothing is passed in or returned. This style
states very clearly that nothing is needed or returned and it
cannot be construed as an oversight. Spend some time studying
these function examples, then begin developing the style you will
use. If you are like most programmers, you will develop a style
that you plan to use forever, then change it every few months or
on every new project.
PROGRAMMING EXERCISES
-----------------------------------------------------------------
1. Rewrite TEMPCONV.C, from an earlier chapter, and move the
temperature calculation to a function.
2. Write a program that writes your name on the monitor 10 times
by calling a function to do the writing. Move the called
function ahead of the main function to see if your C compiler
will allow it.
3. Add prototyping to the programs named SUMSQRES.C and
SQUARES.C, and change the function definitions to the modern
method.
Page 5-12